import patchVnode from './patchVnode'
import createElement from './createElement'
// 判断两个虚拟节点是否为同一个节点
function sameVnode(vnode1, vnode2) {
    return vnode1.key === vnode2.key
}

/**
 * 
 * @param {*} parentElm 旧的父节点
 * @param {*} oldCh 旧的子节点
 * @param {*} newCh 新的子节点
 */
export default function(parentElm, oldCh, newCh) {
    // console.log(parentElm, oldCh, newCh)
    let oldStartIdx = 0 // 旧前指针
    let oldEndIdx = oldCh.length - 1 // 旧后指针
    let newStartIdx = 0 // 新前指针
    let newEndIdx = newCh.length - 1 // 新后指针

    let oldStartVnode = oldCh[0] // 旧前虚拟节点
    let oldEndVnode = oldCh[oldEndIdx] // 旧后虚拟节点
    let newStartVnode = newCh[0] // 新前虚拟节点
    let newEndVnode = newCh[newEndIdx] // 新后虚拟节点

    while(oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
        if(oldStartVnode === undefined) {
            oldStartVnode = [++oldStartIdx]
        }
        if(oldEndVnode === undefined) {
            oldEndVnode = [--oldEndIdx]
        }else if(sameVnode(oldStartVnode, newStartVnode)) {
            // 旧前和新前
            console.log(1)
            patchVnode(oldStartVnode, newStartVnode)
            if(newStartVnode) {
                newStartVnode.elm = oldStartVnode?.elm
            }
            oldStartVnode = oldCh[++oldStartIdx]
            newStartVnode = newCh[++newStartIdx]
        }else if(sameVnode(oldEndVnode, newEndVnode)) {
            // 旧后和新后
            console.log(2)
            patchVnode(oldEndVnode, newEndVnode)
            if(oldEndVnode) {
                newEndVnode.elm = oldEndVnode?.elm
            }
            oldEndVnode = oldCh[--oldEndIdx]
            newEndVnode = newCh[--newEndIdx]
        }else if(sameVnode(oldStartVnode, newEndVnode)) {
            // 旧前和新后
            console.log(3)
            patchVnode(oldStartVnode, newEndVnode)
            if(oldStartVnode) {
                newEndVnode.elm = oldStartVnode?.elm
            }
            // 把旧前指定的节点移动到旧后指向的节点的后面
            parentElm.insertBefore( oldStartVnode.elm, oldEndVnode.elm.nextSibling )
            oldStartVnode = oldCh[++oldStartIdx]
            newEndVnode = newCh[--newEndIdx]
        } else if(sameVnode(oldEndVnode, newStartVnode)) {
            // 旧后和新前
            console.log(4)
            patchVnode(oldEndVnode, newStartVnode)
            if(oldEndVnode) {
                newStartVnode.elm = oldEndVnode?.elm
            }
            // 把旧后指定的节点移动到旧前指向的节点的前面
            parentElm.insertBefore( oldEndVnode.elm, oldStartVnode.elm )
            oldEndVnode = oldCh[--oldEndIdx]
            newStartVnode = newCh[++newStartIdx]
        } else {
            // 以上都不满足条件 ===》查找
            console.log(5)
            // 创建一个对象存虚拟节点
            let keyMap = {}
            for(let i = oldStartIdx;i <= oldEndIdx;i++) {
                const key = oldCh[i]?.key
                if(key) {
                    keyMap[key] = i
                }
            }
            // console.log(keyMap)
            // 在旧节点中寻找前节点指向的节点
            let indxInOld = keyMap[newStartVnode.key]
            if(indxInOld) { // 能找到
                const elmMove = oldCh[indxInOld]
                patchVnode(elmMove, newStartVnode)
                // 处理过的节点，在旧虚拟节点的数组中，设置为undefined
                oldCh[indxInOld] = undefined
                parentElm.insertBefore(elmMove.elm,  oldStartVnode.elm)
            }else { // 不能找到
                // 说明是新节点，需要重新创建
                parentElm.insertBefore(createElement(newStartVnode), oldStartVnode.elm)
            }
            // 新节点指针+1
            newStartVnode = newCh[++newStartIdx]
        }
    }
    // 结束while 只有两种情况 （新增和删除）
    // 1、oldStartIdx > oldEndIdx
    // 2、newStartIdx > newEndIdx
    if(oldStartIdx > oldEndIdx) {
        const before = newCh[newEndIdx + 1] ? newCh[newEndIdx + 1].elm : null
        for(let i = newStartIdx;i <= newEndIdx;i++) {
            parentElm.insertBefore((createElement(newCh[i])), before)
        }
    } else { // 进入删除操作
        for(let i = oldStartIdx;i <= oldEndIdx;i++) {
            // console.log(oldCh[i])
            parentElm.removeChild(oldCh[i].elm)
        }
    }
}